// 服务启动器 - 减少重复代码

use axum::Router;
use sqlx::PgPool;
use std::net::SocketAddr;
use tracing_subscriber::{fmt, layer::SubscriberExt, util::SubscriberInitExt, EnvFilter};

/// 初始化日志系统（支持 JSON 格式）
pub fn init_tracing() {
    if env_or("RUST_LOG_JSON", "false") == "true" {
        tracing_subscriber::registry()
            .with(fmt::layer().json())
            .with(EnvFilter::from_default_env())
            .init();
    } else {
        tracing_subscriber::registry()
            .with(fmt::layer())
            .with(EnvFilter::from_default_env())
            .init();
    }
}

/// 获取环境变量或默认值
pub fn env_or(key: &str, default: &str) -> String {
    std::env::var(key).unwrap_or_else(|_| default.to_string())
}

/// 启动服务（带追踪中间件）
pub async fn start_service(
    service_name: &str,
    port: &str,
    router: Router,
) -> anyhow::Result<()> {
    use axum::middleware;
    use tower_http::trace::TraceLayer;

    let app = router
        .layer(TraceLayer::new_for_http())
        .layer(middleware::from_fn(add_trace_id));

    let addr: SocketAddr = format!("0.0.0.0:{}", port).parse()?;
    tracing::info!("{} listening on {}", service_name, addr);

    let listener = tokio::net::TcpListener::bind(addr).await?;
    axum::serve(listener, app).await?;

    Ok(())
}

/// 添加追踪 ID 中间件
async fn add_trace_id(
    mut req: axum::http::Request<axum::body::Body>,
    next: axum::middleware::Next,
) -> axum::response::Response {
    use axum::http::HeaderValue;
    
    let trace_id = req
        .headers()
        .get("x-trace-id")
        .and_then(|v| v.to_str().ok())
        .map(|s| s.to_string())
        .unwrap_or_else(|| uuid::Uuid::new_v4().to_string());

    if !req.headers().contains_key("x-trace-id") {
        req.headers_mut().insert("x-trace-id", HeaderValue::from_str(&trace_id).unwrap());
    }

    tracing::info!(trace_id = %trace_id, "Request received");
    
    let mut response = next.run(req).await;
    response.headers_mut().insert("x-trace-id", HeaderValue::from_str(&trace_id).unwrap());
    response
}

/// 创建数据库连接池（重复代码提取）
pub async fn init_db(url_key: &str, default_url: &str) -> anyhow::Result<PgPool> {
    let url = env_or(url_key, default_url);
    database::create_pool(&url, 20).await
}

